// 附件服务接口

package misc

import (
	"crypto/md5"
	"dhfshop/controllers/base"
	"dhfshop/models/misc"
	"errors"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/validation"
	"github.com/satori/go.uuid"
	"io/ioutil"
	"os"
	"path"
	"strconv"
	"strings"
)

var uploadFilePath string = "static/uploads"

// 公共-附件管理服务
type AttachmentController struct {
	base.BaseController
}

// 上传附件
func (this *AttachmentController) CreateAttachment() {
	companyId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	file, fileHeader, err := this.GetFile("wxfile")
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	categoryId := this.GetString("categoryId")
	//
	contentType := fileHeader.Header.Get("Content-Type")
	originalFilename := fileHeader.Filename
	ext := path.Ext(originalFilename)
	clientUId := uuid.NewV4().String() + ext
	attachment := misc.Attachment{
		CompanyId:    companyId,
		CreatorId:    curUserId,
		UUId:         clientUId,
		OriginalName: originalFilename,
		Mime:         contentType,
	}
	if len(categoryId) > 0 {
		attachment.CategoryId, _ = strconv.ParseInt(categoryId, 10, 64)
	}
	//beego.Debug("CreateAttachment companyId:", companyId)
	buf, err := ioutil.ReadAll(file)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	attachment.Md5Hash = this.getFileMd5(buf)
	if oldAttachment, err := misc.GetAttachByMd5Hash(attachment.Md5Hash); err == nil {
		//当前用户的重复上传，返回错误提示
		if ok := misc.CheckAttachHashExist(attachment.CreatorId, attachment.Md5Hash); ok {
			beego.Debug("The same user file MD5 is exist:", attachment.Md5Hash)
			this.Data["json"] = oldAttachment
			this.ServeJSON()
		} else { //非当前用户的重复上传，不需要存储文件，但需要写入记录
			beego.Debug("Not the same user file MD5 is exist:", attachment.Md5Hash)
			attachment.Size = oldAttachment.Size
			attachment.URL = oldAttachment.URL
			if attachment.Id, err = misc.CreateAttachment(&attachment); err != nil {
				this.ServeError(err.Error())
				return
			}
			this.Data["json"] = attachment
			this.ServeJSON()
		}
	}
	fileLen, err := file.Seek(0, os.SEEK_END)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	_, err = file.Seek(0, os.SEEK_SET)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	attachment.Size = uint64(fileLen)
	file.Close()
	//
	if _, err := os.Stat(uploadFilePath); os.IsNotExist(err) {
		os.Mkdir(uploadFilePath, 0777)
	}
	filePath := uploadFilePath + "/" + attachment.UUId
	err = this.SaveToFile("wxfile", filePath)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	attachment.URL = "/" + filePath
	if attachment.Id, err = misc.CreateAttachment(&attachment); err != nil {
		this.ServeError(err.Error())
		return
	}
	this.Data["json"] = attachment
	this.ServeJSON()
}

// 更新附件
func (this *AttachmentController) UpdateAttachment() {
	uuid := this.GetString("uuid")
	attachment, err := misc.GetAttachmentByUuid(uuid)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	oldAttachmentURL := attachment.URL
	file, fileHeader, err := this.GetFile("attachments")
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	contentType := fileHeader.Header.Get("Content-Type")
	originalFilename := fileHeader.Filename
	//ext := path.Ext(originalFilename)
	attachment.OriginalName = originalFilename
	attachment.Mime = contentType
	fileLen, err := file.Seek(0, os.SEEK_END)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	_, err = file.Seek(0, os.SEEK_SET)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	attachment.Size = uint64(fileLen)
	if _, err := os.Stat(uploadFilePath); os.IsNotExist(err) {
		os.Mkdir(uploadFilePath, 0777)
	}
	filePath := uploadFilePath + "/" + attachment.UUId
	err = this.SaveToFile("attachments", filePath)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	attachment.URL = "/" + filePath
	if err := misc.UpdateAttachment(attachment, "OriginalName", "Name", "Mime", "Size"); err != nil {
		this.ServeError(err.Error())
		return
	}
	os.Remove(oldAttachmentURL)
	this.Data["json"] = attachment
	this.ServeJSON()
}

// @Title 增加有权查看附件的人员
func (this *AttachmentController) AddViewer() {

}

// @Title 删除有权查看附件的人员

func (this *AttachmentController) RemoveViewer() {

}

// @Title 将附件设定为公开

func (this *AttachmentController) PublicAttachment() {

}

// @Title 删除附件

func (this *AttachmentController) DeleteAttachment() {
	uuid := this.GetString("uuid")
	attachment, err := misc.GetAttachmentByUuid(uuid)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	if err = misc.DeleteAttachmentByUuid(uuid); err != nil {
		this.ServeError(err.Error())
		return
	}
	if err = os.Remove(attachment.URL); err != nil {
		this.ServeError(err.Error())
		return
	}
	this.ServeJSON()
}

// @Title 根据UUID获取附件

func (this *AttachmentController) GetByUUID() {

}

func (this *AttachmentController) GetAttachPara() (string, string, string, map[string]string, []string, map[string]string, int, int, error) {
	query := make(map[string]string)
	fields := []string{}
	order_by := make(map[string]string)
	offset := 0 //default is 0
	limit := 10 //default is 50
	v := struct {
		Fields       string `form:"fields"`
		PageSize     int    `form:"page_size"`
		PageNo       int    `form:"page_no"`
		StartCreated string `form:"start_created"`
		EndCreated   string `form:"end_created"`
		Mime         string `form:"mime"`
		Query        string `form:"query"`
		OrderBy      string `form:"order_by"`
	}{PageSize: 10, PageNo: 1}
	this.ParseForm(&v)
	valid := validation.Validation{}
	valid.Range(v.PageSize, 1, 1000, "page_size")
	valid.Range(v.PageNo, 1, 1000, "page_no")
	passed, _ := valid.Valid(&v)
	if !passed {
		err := errors.New(valid.Errors[0].Key + " " + valid.Errors[0].Message)
		return v.StartCreated, v.EndCreated, v.Mime, query, fields, order_by, offset, limit, err
	}
	v.PageNo = v.PageNo - 1 //为了计算offset
	if len(v.Fields) > 2 {
		fields = strings.Split(v.Fields, ",")
	}
	if len(v.Query) > 2 {
		for _, cond := range strings.Split(v.Query, ",") {
			kv := strings.Split(cond, ":")
			if len(kv) != 2 {
				err := errors.New("Error: invalid query key/value pair")
				return v.StartCreated, v.EndCreated, v.Mime, query, fields, order_by, offset, limit, err
			}
			k, v := kv[0], kv[1]
			query[k] = v
		}
	}
	if len(v.OrderBy) > 2 {
		for _, cond := range strings.Split(v.OrderBy, ",") {
			kv := strings.Split(cond, ":")
			if len(kv) != 2 {
				err := errors.New("Error: invalid order_by key/value pair")
				return v.StartCreated, v.EndCreated, v.Mime, query, fields, order_by, offset, limit, err
			}
			k, v := kv[0], kv[1]
			order_by[k] = v
		}
	}
	offset = v.PageNo * v.PageSize
	limit = v.PageSize
	return v.StartCreated, v.EndCreated, v.Mime, query, fields, order_by, offset, limit, nil
}

func (this *AttachmentController) GetAll() {
	start, end, mime, query, fields, order_by, offset, limit, err := this.GetAttachPara()
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	curRoleId := this.Ctx.Input.GetData("curRoleId").(int)
	companyId := int64(this.Ctx.Input.GetData("curCompanyId").(int))
	curUserId := int64(this.Ctx.Input.GetData("curUserId").(int))
	if curRoleId == 1 {
		query["creator_id"] = strconv.FormatInt(curUserId, 10)
	} else if curRoleId == 2 {
		query["company_id"] = strconv.FormatInt(companyId, 10)
	} else {

	}
	l, cnt, err := misc.GetAllAttachments(start, end, mime, query, fields, order_by, offset, limit)
	if err != nil {
		this.ServeError(err.Error())
		return
	}
	r := struct {
		TotalCount int64              `json:"total_count"`
		Attachment []*misc.Attachment `json:"attachment"`
	}{TotalCount: cnt, Attachment: l}
	this.Data["json"] = r
	this.ServeJSON()
}

func (this *AttachmentController) getFileMd5(buf []byte) string {
	hash := md5.New()
	hash.Write(buf)
	return fmt.Sprintf("%x", hash.Sum(nil))
}
